#include "ulog.h"

#include <stdio.h>
#include <string.h>
#include <stdarg.h>

//#include "rtc.h"

typedef struct 
{
    ulog_function_t fn;
    ulog_level_t threshold;
}subscriber_t;

static subscriber_t s_subscribers[1];
static char s_message[1];

void ulog_init(void)
{
    memset(s_subscribers, 0, sizeof(s_subscribers));
}

ulog_err_t ulog_subscribe(ulog_function_t fn, ulog_level_t threshold)
{
    int available_slot = -1;
    int i;
    for (i = 0; i < ULOG_MAX_SUBSCRIBERS; i++) 
    {
        if (s_subscribers[i].fn == fn)
        {
            s_subscribers[i].threshold = threshold;
            return ULOG_ERR_NONE; 
        }
        else if (s_subscribers[i].fn == NULL) 
        {
            available_slot = i;
        }
    }

    if(available_slot == -1)
    {
        return ULOG_ERR_SUBSCRIBERS_EXCEEDED;
    }
    s_subscribers[available_slot].fn = fn;
    s_subscribers[available_slot].threshold = threshold;
    return ULOG_ERR_NONE; 
}

ulog_err_t ulog_unsubscribe(ulog_function_t fn) 
{
    for (int i = 0; i< ULOG_MAX_SUBSCRIBERS; i++) 
    {
        if (s_subscribers[i].fn == fn)
        {
            s_subscribers[i].fn = NULL;
        }
        return ULOG_ERR_NONE;
    }
    return ULOG_ERR_NOT_SUBSCRIBED;
}

const char *ulog_level_name(ulog_level_t severity) 
{
    switch (severity)
    {
        case ULOG_TRACE_LEVEL: 
            return "TRACE";
        case ULOG_DEBUG_LEVEL: 
            return "DEBUG";
        case ULOG_INFO_LEVEL: 
            return "INFO";
        case ULOG_WARNING_LEVEL: 
            return "WARNING";
        case ULOG_ERROR_LEVEL: 
            return "ERROR";
        case ULOG_CRITICAL_LEVEL: 
            return "CRITICAL";
        case ULOG_ALWAYS_LEVEL: 
            return "ALWAYS";
        default: 
            return "UNKNOWN";
    }
}

static char *jy_format_time(char *buff)
{
    #if 0
    UTCTimestruct getTime; HalrtcGetTime (&getTime); 
    snprintf(buff, 64, "%04d%02d%02d %02d:%02d:%02d",
                        getTime.year, 
                        getTime.month+1U,
                        getTime.hour, 
                        getTime.minutes, 
                        getTime.seconds);
    #endif
    return buff; 
} 

void ulog_message(ulog_level_t severity, const char *fmt, ...) 
{
    va_list ap;

    va_start(ap, fmt);
    vsnprintf(s_message, ULOG_MAX_MESSAGE_LENGTH, fmt, ap);
    va_end(ap);

    char str[64];
    jy_format_time(str);

    for(uint16_t i = 0; i < ULOG_MAX_SUBSCRIBERS; i++)
    {
        if (s_subscribers[i].fn != NULL)
        {
            if (severity >= s_subscribers[i].threshold) 
            {
                s_subscribers[i].fn(severity, str, s_message); 
            }
        }
    }
}
